﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Text;

namespace DataProcessing
{
    /// <summary>
    /// 最重要的类，记载了chrome的信息
    /// </summary>
    public class ChromePairData
    {
        public enum AlignMode
        {
            LeftJustify, CenterJustify
        };

        static public AlignMode Align
        {
            get;
            set;
        }
      
        public static ChromePairData[] Data
        {
            get;
            set;
        }


        public List<ChrSampling> ChromeSampling
        {
            get;set;
        
        }


        public String Name
        {
            get;
            set;
        }
        public uint Number
        {
            get;
            set;

        }

        /// <summary>
        /// 当前窗口内有多少个“逻辑点”
        /// </summary>
        public const int RESOLUTION = 512;
        


        /// <summary>
        /// 所有基因对的当前窗口中最大值
        /// </summary>
        public static uint ALL_CurrentAccumulation_Max
        {
            get;
            set;
        }
        public uint CurrentAccumulation_Max
        {
            get;
            set;
        }
        public ValueRange CurrentWindow
        {
            get;
            set;
        }


        public CalculationCache[] CurrentCache
        {
            get;
            set;
        }

        /// <summary>
        /// 根据设置中的align 模式来计算窗口范围
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public ValueRange GetActualWindow(ValueRange input)
        {


            if (Align != AlignMode.CenterJustify)
                return input;
            ValueRange newRange = new ValueRange();

            newRange.Start = GetActualPoint(input.Start);
            newRange.End = GetActualPoint(input.End);

            return newRange;
        }

        public uint GetActualPoint(uint input)
        {
            if (Align != AlignMode.CenterJustify)
                return input;
            int index = (int)Number;


            uint offset = (uint)Settings.Instance.ChromeSettingList[index].Offset;
            return (input > offset ? input- offset : 0);
        }

        /// <summary>
        /// prepare according to resolution
        /// </summary>
        private void PrepareGlobalData()
        {
            CurrentWindow = ChromePairData.AllWindowMax;

            CurrentCache = FastCalculation.ComputeCache(this.Number, CurrentWindow, RESOLUTION,true);
            FindAccumulationMax();
        }

        private void FindAccumulationMax()
        {
            CurrentAccumulation_Max = 0;
            for (int i = 0; i < RESOLUTION; i++)
            {
                CurrentAccumulation_Max = Math.Max(CurrentAccumulation_Max, CurrentCache[i].Accumulation);
            }
        }


        /// <summary>
        /// after zoom in/out , we are limited into a smaller window
        /// </summary>
        /// <param name="newWindow"></param>
        /// <returns></returns>
        public uint[] GetAccumulations()
        {
            uint[] ret = new uint[RESOLUTION];
   
            for (int i = 0; i < RESOLUTION; i++)
            {
                ret[i] = this.CurrentCache[i].Accumulation;
            }
            return ret;
        }

        public void AddSample(ChrSampling sample)
        {
            this.CurrentWindow.End = Math.Max(sample.End, CurrentWindow.End);
            CurrentWindow.Start = Math.Min(sample.Begin, CurrentWindow.Start);

            this.ChromeSampling.Add(sample);
        }

        /// <summary>
        /// 全局值域范围，由第一次读入文件时候设置
        /// </summary>
        static public ValueRange BoundWindow;
        public ChromePairData()
        {
            ChromeSampling = new List<ChrSampling>();
            CurrentWindow = new ValueRange();
            //yes, start>end, but it will be corrected after sampling data come in
            CurrentWindow.Start = UInt32.MaxValue;
            //will be overrided after loading data.
            CurrentWindow.End = UInt32.MinValue;

            CurrentWindow = new ValueRange();
            CurrentAccumulation_Max = 0;
            
            
        }

        public static ValueRange AllWindowMax
        {
            get;
            set;
        }


        static private void FindCurrentMaxAccumulationAll()
        {
            ALL_CurrentAccumulation_Max = 0;

            //纵向窗口像最大的取齐
            int i = 0;
            for (i = 0; i < Data.Length; i++)
            {
                ALL_CurrentAccumulation_Max = Math.Max(Data[i].CurrentAccumulation_Max, ALL_CurrentAccumulation_Max);
            }
        }

        static private void NormalizeWindow(ChromePairData[] values)
        {
          
            AllWindowMax.Start = uint.MaxValue;
            AllWindowMax.End = uint.MinValue;
            //1.横向窗口按照最大的取齐for
            int i=0;
            for (i = 0; i < values.Length; i++)
            {
                AllWindowMax.Start = Math.Min(values[i].CurrentWindow.Start, AllWindowMax.Start);
                AllWindowMax.End = Math.Max(values[i].CurrentWindow.End, AllWindowMax.End);
            }
            if (ChromePairData.Align == AlignMode.CenterJustify)
            {
                //AllWindowMax.End += (uint)Settings.Instance.MaxOffset;
            }
            
            for (i = 0; i < values.Length; i++)
            {
                values[i].CurrentWindow.Start = AllWindowMax.Start;
                values[i].CurrentWindow.End = AllWindowMax.End;
            }
            
           
           
        }

        /// <summary>
        /// 修改一点。即可支持align point
        /// </summary>
        /// <returns></returns>
        private uint PrepareCurrentData()
        {
            CurrentAccumulation_Max = 0;
            uint ret = 0;
            CurrentCache = FastCalculation.ComputeCache(this.Number, CurrentWindow, RESOLUTION,true);
            FindAccumulationMax();
            return ret;
        }

        static public void PrepareAllCurrentData()
        {
            if (ChromePairData.Data == null)
                return;
            Parallel.For(0, ChromePairData.Data.Length, i =>
            {
                ChromePairData.Data[i].PrepareCurrentData();
            });

            ChromePairData.FindCurrentMaxAccumulationAll();
        }

        /// <summary>
        /// 回到全局window
        /// </summary>
        static public void BackToGlobalView()
        {
            for (int i = 0; i < Data.Length; i++)
            {
                Data[i].CurrentWindow = BoundWindow.Clone();
            }
            AllWindowMax = BoundWindow.Clone();
        }

        static public void Initialize(bool recordBound=false)
        {
            DateTime t1, t2;
            t1 = DateTime.Now;
            AllWindowMax = new ValueRange();
            
            //1 归一化窗口
            NormalizeWindow(Data);

            //此处需要记住全局边界
            if (recordBound)
            {
                BoundWindow = AllWindowMax.Clone();
            }
            FastCalculation.Init();

            //2 对每一个对基因，prepare
            Parallel.For(0, ChromePairData.Data.Length, i =>
            {
                ChromePairData.Data[i].PrepareGlobalData();
            });
            FindCurrentMaxAccumulationAll();
            t2 = DateTime.Now;
            
           
            
            double elapse = (t2 - t1).TotalMilliseconds;
        }
   
    }
}
